package com.lyf.boot.auth;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.lyf.boot.base.system.entity.SysClient;
import com.lyf.boot.base.user.dao.BaseUserDao;
import com.lyf.boot.base.user.entity.User;
import com.lyf.boot.constant.Constant;
import com.lyf.boot.constant.RedisConstant;
import com.lyf.boot.core.model.LoginUser;
import com.lyf.boot.core.model.LoginVo;
import com.lyf.boot.core.service.IAuthStrategy;
import com.lyf.boot.enums.SmsType;
import com.lyf.boot.exception.ServiceException;
import com.lyf.boot.modules.index.entity.dto.LoginSmsDto;
import com.lyf.boot.properties.AuthProperties;
import com.lyf.boot.utils.AuthUtil;
import com.lyf.boot.utils.JsonUtil;
import com.lyf.boot.utils.RedisUtil;
import com.lyf.boot.utils.ValidatorUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author Luyufan
 * @date 2024/1/11 09:17
 **/
@Slf4j
@Service("sms" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class SmsAuthStrategy implements IAuthStrategy {

    private final BaseUserDao baseUserDao;

    private final AuthProperties authProperties;
    @Override
    public LoginVo login(String body, SysClient client) {
        LoginSmsDto loginDto = JsonUtil.parseObject(body, LoginSmsDto.class);
        if(null == loginDto){
            throw new ServiceException("登录参数异常");
        }
        //校验参数
        ValidatorUtil.validate(loginDto);
        String phoneNumber = loginDto.getPhoneNumber();
        String smsCodeKey = null;
        List<String> noLoginList = authProperties.getNoLoginList();
        if(CollUtil.isEmpty(noLoginList) || !CollUtil.contains(noLoginList, phoneNumber)){
            smsCodeKey = StrUtil.format(RedisConstant.SMS_CODE_KEY, SmsType.LOGIN.name(), loginDto.getPhoneNumber());
            if(!RedisUtil.hasKey(smsCodeKey)){
                throw new ServiceException("验证码已失效");
            }
            if(ObjectUtil.notEqual(loginDto.getSmsCode(), RedisUtil.getCacheObject(smsCodeKey))){
                throw new ServiceException("验证码不正确");
            }
        }
        User user = baseUserDao.selectOne(Wrappers.<User>lambdaQuery()
                .eq(User::getPhoneNumber, phoneNumber));
        Assert.notNull(user, "账号不存在");
        Assert.equals(Constant.ONE, user.getStatus(), "账号已被冻结");
        Long userId = user.getUserId();
        LoginUser loginUser = new LoginUser().setUserId(userId)
                .setUsername(user.getUsername())
                .setRealName(user.getRealName())
                .setNickName(user.getNickName());
        SaLoginModel model = new SaLoginModel();
        model.setDevice(client.getDeviceType());
        model.setTimeout(client.getTimeout());
        model.setActiveTimeout(client.getActiveTimeout());
        model.setExtra(AuthUtil.CLIENT_KEY, client.getClientCode());
        AuthUtil.login(loginUser, model);
        if(StrUtil.isNotBlank(smsCodeKey)){
            RedisUtil.deleteObject(smsCodeKey);
        }
        return new LoginVo()
                .setAccessToken(StpUtil.getTokenValue())
                .setExpireIn(StpUtil.getTokenTimeout())
                .setClientCode(client.getClientCode())
                .setUserId(AuthUtil.getUserId());
    }
}
